/* 算法实现模板 */
import AlgorithmBase from "./AlgorithmBase";
import {toKatexString,toVector} from "../../../common/Vector";
import 'katex/dist/katex.min.css';
import { showMathStringInTable } from "../../../visual/Table2D";
import NumpyJS from 'jsnumpy';
import { mdRender } from "../../../common/Common";



class Viterbi extends AlgorithmBase{
  constructor(){
    super('Viterbi');
    this.descriptionUrl = `${this.homepage}/data/slm/ch10/10.5/readme.md`;
    this.datasetUrl = `${this.homepage}/data/slm/ch9/9.1/dataset.json`;
  }
  init(){ 
    this.reset();
    this.initTrainDS();
  }
  
  reset(){
    // this.dataset = undefined;
    // this.trainDS = undefined;
    this.clear();
    this.initDescription();
    this.updateModel();
  }
  
  loadModel(json){
    if(json.TrainDS){
      this.trainDSList = [];
      if(json.TrainDS instanceof Array){
        for(let i = 0, il = json.TrainDS.length; i < il; i++){
          const newTrain = json.TrainDS[i];
          newTrain.T = toVector(newTrain.T, true);
          this.trainDSList.push(newTrain);
        }
        this.trainDS = this.trainDSList[0];
      }
      else{
        this.trainDS = json.TrainDS.x;
      }
    }
    mdRender(`$A:[[0.5, 0.2, 0.3],[0.3, 0.5, 0.2],[0.2, 0.3, 0.5]] \\ ,B:[[0.5, 0.5],[0.4, 0.6],[0.7, 0.3]] \\ , \pi:[0.2, 0.4, 0.4]$,已知观测序列O=(红,白,红)，试求最优路径`,this.inputDiv)
    
  }

  initDescription(){
    fetch(this.descriptionUrl).then((response)=>{
      return response.text();
    }).then((txt)=>{

      this.reandMD(txt, this.descriptionDiv)
    })
  }
  
  initTrainDS(){
    this.prepare(this.datasetUrl);
  }


  // 准备数据训练数据
  prepare(url){
    fetch(url).then((response)=>{
      return response.json();
    }).then((json)=>{
      this.trainDS = this.loadModel(json);
      this.updateModel();
    })
  }

  openFileSelector(){
    this.fileSelector.click();
  }

  // 获取文件路径加载
  handleFileChange(event){
    const files = event.target.files;

    for(let i = 0, il = files.length; i < il; i++){
      let reader = new FileReader();
      reader.onload = (e) => {      
        this.prepare(e.target.result);
        if(i === files.length - 1){
          event.target.value = '';
        }
      };
      reader.readAsDataURL(files[i])
    }
  }

   // 输入数据UI
   initInputUI(){

    // 文件选择器
    const fileSelector      = document.createElement('input');
    fileSelector.type       = 'file';
    fileSelector.hidden     = true;
    fileSelector.onchange   = this.handleFileChange.bind(this);   
    
    this.addButton(this.domElementList.input, "获取服务器数据", this.initTrainDS.bind(this));
    this.addButton(this.domElementList.input, "使用本地数据", this.openFileSelector.bind(this));
    this.domElementList.input.appendChild(fileSelector);
    this.addButton(this.domElementList.input, "训练", this.train.bind(this));
    this.labelTrainTips = this.addLabel(this.domElementList.input, '');
    this.inputDiv       = this.addDiv(this.domElementList.input);
    this.fileSelector  = fileSelector;
  }


  // 输出UI
  initOutputUI(){
    this.outputDiv   = this.addDiv(this.domElementList.output);
    this.trainLogDiv = this.addDiv(this.domElementList.output);
  }
  find_max(list){
    var max = list[0];
    for(var i=0;i<list.length;i++){
      if(max<list[i]){
        max = list[i];
      }
    }
    return max;
  }
  
  Viterbi_decode(hmm_paramter,obs_idx_seq){
    var A = hmm_paramter[0];
    var B = hmm_paramter[1];
    var L = hmm_paramter[2];
    var N = A[0].length;
    var T = obs_idx_seq.length;
    var p = [[0,0,0],[0,0,0],[0,0,0]];
    var D = [[0,0,0],[0,0,0],[0,0,0]];
    for(var m=0;m<N;m++){
      p[m][0] = (L[m]*(B[m][0])) ;
      D[m][0] = -1;
    }
    console.log(p)
    for(var i=1;i<T;i++){
      var obs_value = obs_idx_seq[i];
      for(var j=0;j<N;j++){
        var pro_list = [];
        for(var k=0;k<N;k++){
          pro_list.push(p[k][i-1]*A[k][j]*B[j][obs_value]); 
        }
        var max_value = this.find_max(pro_list);
        var max_idx = pro_list.findIndex(max => max === max_value);
        p[j][i] = max_value;
        D[j][i] = max_idx;
      }
    }
    var final_max_value = p[2][2];
    var final_max_inx = 2;
    var state_list = [];
    state_list.push(final_max_inx);
    for(var i = T-1;i>0;i--){
      final_max_inx = D[final_max_inx][i];
      state_list.push(final_max_inx);
    }
    var final_state_list = [];
    for(var i =state_list.length-1;i>-1;i--){
      final_state_list.push(state_list[i]+1)
    }
    return {
    final_max_value,
    final_state_list}

  }
  

  train(){
    var hmm_paramter = [[[0.5, 0.2, 0.3],[0.3, 0.5, 0.2],[0.2, 0.3, 0.5]],[[0.5, 0.5],[0.4, 0.6],[0.7, 0.3]],[0.2, 0.4, 0.4]];
    var O = ['红','白','红'];
    var obs_to_idx = {'红': 0, '白': 1};
    var obs_seq_idx = [];
    for(var i=0;i<O.length;i++){
      obs_seq_idx.push(obs_to_idx[O[i]])
    }
    var final_max_value= this.Viterbi_decode(hmm_paramter,obs_seq_idx).final_max_value;
    var final_state_list = this.Viterbi_decode(hmm_paramter,obs_seq_idx).final_state_list;
    mdRender(`最优路径概率 P = ${final_max_value} 
     最优路径 I = [${final_state_list}] `, this.outputDiv)
    
  }
  updateModel(){


  }

}



export default Viterbi;